
#include <gfx/ieffect.h>
#include <gfx/ieffectprogram.h>
#include <gfx/iindexbuffer.h>
#include <gfx/iprogram.h>
#include <gfx/ivertexbuffer.h>
#include <gfx/ivertexdeclaration.h>
#include <gfx/material.h>
#include <utils/cameraprojectorsetup.h>
#include <scene_editor/sceneeditor.h>
#include <transformationeditdialog.h>
#include <session.h>
#include <stdio.h>
#include <QKeyEvent>
#include <QPlatformWindowFormat>
#include <QGridLayout>
#include <QComboBox>

static QGLContext* create_qgl_context ()
{
  QGLFormat format = QGLFormat::defaultFormat();

  QGLContext* context = new QGLContext(format);
  if (!context->create(0))
    {
      printf ("Unable to create GL-Context\n");
      fflush(stdout);
      delete context;
      context = 0;
    }
  return context;
}

static QGLFormat get_format ()
{
  QGLFormat fmt;
  fmt.setVersion(3, 2);
  return fmt;
}

static QGLWidget* shared_widget = 0;


SceneEditorWidget::SceneEditorWidget(QWidget *parent)
  : QGLWidget( parent, shared_widget)
  , iWindow()
	, _scene(0)
  , _controlerSector (0)
  , _physicsWorld(0)
  , _boundingBoxMesh(0)
  , _boundingBoxNode(0)
  , _boundingBoxNodeVisible(false)
  , _transformationEditor (0)
  , _transformerHandle(0)
  , _transformerCoordinates(TransformerCoordinates_Local)
  , _addSelection(false)
  , _rotH(0.0f)
  , _rotV(0.0f)
  , _dist(100.0f)
  , _handleMode(HandleMode_Idle)
  , _keys (0)
  , _buttons (0)
{
  _selectedNodes.clear();
  CE_OBJECT_CONSTR
  if (!shared_widget)
    {
      shared_widget = this;
    }
  setFocusPolicy(Qt::StrongFocus);
  setMouseTracking(true);
  connect (this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(customContextMenuRequested(const QPoint&)));
}

TransformationEditDialog* SceneEditorWidget::GetTransformationEditor()
{
  if (!_transformationEditor)
    {
      _transformationEditor = new TransformationEditDialog(this);
      _transformationEditor->setVisible(false);
      _transformationEditor->setModal(false);
      _transformationEditor->SetTransformer (&_transformer);
      connect (_transformationEditor, SIGNAL(TransformationChanged()), this, SLOT(TransformationChanged()));
    }
  return _transformationEditor;
}



bool SceneEditorWidget::IsCameraIdle() const
{

  return !(
      _handleMode == HandleMode_Camera ||
      (Key(Key_Ctrl) && _buttons != 0));
}

void SceneEditorWidget::keyPressEvent(QKeyEvent *event)
{
  switch (event->key())
    {
    case Qt::Key_Control:
      _keys |= Key_Ctrl;
      break;

    case Qt::Key_Shift:
      _keys |= Key_Shift;
      break;

    case Qt::Key_Alt:
      _keys |= Key_Alt;
      break;

    }

  Grab (true);
}

void SceneEditorWidget::keyReleaseEvent(QKeyEvent *event)
{
  switch (event->key())
    {
    case Qt::Key_Control:
      _keys &= ~Key_Ctrl;
      if (_handleMode == HandleMode_Camera)
        {
          _handleMode = HandleMode_Idle;
        }
      break;

    case Qt::Key_Shift:
      _keys &= ~Key_Shift;
      break;

    case Qt::Key_Alt:
      _keys &= ~Key_Alt;
      break;

    case Qt::Key_N:
      {
        TransformationEditDialog* editor = GetTransformationEditor();
        editor->setVisible(true);
        editor->UpdateGUI ();

      }
      break;
    case Qt::Key_C:
      {
        CenterCameraOnTransformation ();
      }
      break;

    }


  Grab(false);
}

void SceneEditorWidget::mousePressEvent(QMouseEvent *event)
{
  _prevX = event->x();
  _prevY = event->y();
  switch (event->button())
    {
     case Qt::LeftButton:
      _leftMousePressPositionX = event->x();
      _leftMousePressPositionY = event->y();
      _buttons |= Button_Left;
      break;

    case Qt::RightButton:
      _buttons |= Button_Right;
      break;

    case Qt::MiddleButton:
      _buttons |= Button_Middle;
      break;
    }

  Grab(true);

  if (!Key(Key_Ctrl) && !Key(Key_Alt) && !Key(Key_Shift) && event->button() == Qt::LeftButton)
    {

      if (TestTransformerHandle(event->x(), event->y()))
        {
          _handleMode = HandleMode_Transformation;
        }
    }
}

void SceneEditorWidget::mouseReleaseEvent(QMouseEvent *event)
{
  /* reset the mouse states */
  switch (event->button())
    {
     case Qt::LeftButton:
      _buttons &= ~Button_Left;
      break;

    case Qt::RightButton:
      _buttons &= ~Button_Right;
      break;

    case Qt::MiddleButton:
      _buttons &= ~Button_Middle;
      break;
    }

  Grab (false);

  if (_handleMode == HandleMode_Idle)
    {
      switch (event->button())
        {
        case Qt::LeftButton:
          // perform the selection
          {
            SelectMode mode = Select_Replace;
            if (Key(Key_Ctrl))
              {
                mode = Select_Add;
              }
            else if (Key(Key_Shift))
              {
                mode = Select_Sub;
              }
            DoPointSelection(event->x(), event->y(), mode);

          }
        }
    }
  else if (_handleMode == HandleMode_Transformation)
    {
      switch (event->button())
        {
        case Qt::LeftButton:
          _transformer.ApplyTransformation();
          UpdateTransformationHandlerMatrix();
          _transformerHandle->ClearActive();
          break;
        case Qt::RightButton:
        case Qt::MiddleButton:
          _transformer.ResetTransformation();
          UpdateTransformationHandlerMatrix();
          _transformerHandle->ClearActive();
          break;
        }
    }


  // at last reset the camera state
  _handleMode = HandleMode_Idle;


}

void SceneEditorWidget::mouseMoveEvent(QMouseEvent *event)
{
  int relx = event->x() - _prevX;
  int rely = event->y() - _prevY;
  _prevX = event->x();
  _prevY = event->y();

  if (Key (Key_Ctrl))
    {
      CameraMode mode = CameraMode_Idle;
      // the control is pressed so we start some camera action
      if (_handleMode == HandleMode_Idle || _handleMode == HandleMode_Camera)
        {
          if (Button(Button_Left))
            {
              mode = CameraMode_Rotate;
              _handleMode = HandleMode_Camera;
            }
          else if (Button(Button_Right))
            {
              mode = CameraMode_Translate;
              _handleMode = HandleMode_Camera;
            }
          else if (Button(Button_Middle))
            {
              mode = CameraMode_Zoom;
              _handleMode = HandleMode_Camera;
            }
        }
      else
        {
          if (!Button(Button_Left) && !Button(Button_Middle) && !Button(Button_Right))
            {
              mode = CameraMode_Idle;
              _handleMode = HandleMode_Idle;

            }
        }


      switch (mode)
        {
        case CameraMode_Rotate:
          handleCameraRotate (relx, rely);
          emit Changed();
          break;
        case CameraMode_Translate:
          handleCameraTranslate (relx, rely);
          emit Changed();
          break;
        case CameraMode_Zoom:
          handleCameraZoom(relx, rely);
          emit Changed();
          break;
        default:
          break;
        }
    }
  else
    {
      if (_handleMode == HandleMode_Transformation)
        {
          if (_transformerHandle && _transformerHandle->IsActive())
            {
              DoTransformation (event->x(), event->y());
            }
        }
      else
        {
          _handleMode = HandleMode_Idle;
        }

    }
}

void SceneEditorWidget::customContextMenuRequested(const QPoint&)
{
  if (IsCameraIdle())
    {
      _keys = 0;
      _buttons = 0;
      Grab(false);
    }
}

void SceneEditorWidget::Grab (bool grab)
{
  static bool is_grabbed = false;

  if (grab)
    {
      if (is_grabbed)
        {
          return;
        }

      grabKeyboard();
      grabMouse();
      is_grabbed = true;
    }
  else
    {
      if (!is_grabbed || _keys != 0 || _buttons != 0)
        {
          return;
        }
      releaseKeyboard();
      releaseMouse();
    }
}

void SceneEditorWidget::handleCameraRotate(int relx, int rely)
{
  _rotV -= (float)relx / 100.0f;
  _rotH += (float)rely / 100.0f;
  updateCamera();
  repaint ();
}

void SceneEditorWidget::handleCameraTranslate(int relx, int rely)
{
  ceVector3f d (_dist * 2.0f * (float)relx / (float)width(),
                0.0f,
                _dist * 2.0f * (float)rely / (float)height());
  _spot = _spot + _cameraMatrix * d;
  updateCamera();
  repaint ();
}

void SceneEditorWidget::handleCameraZoom(int relx, int rely)
{
  if (rely < 0)
    {
      rely = -rely;
      _dist = _dist * pow(0.99, rely);
    }
  else
    {
      _dist = _dist * pow(1.01, rely);
    }
  updateCamera();
  repaint ();
}

void SceneEditorWidget::updateCamera()
{
  ceMatrix4f MrotH;
  MrotH.SetIdentity();
  MrotH.SetRotationX(_rotH);

  ceMatrix4f MrotV;
  MrotV.SetIdentity();
  MrotV.SetRotationZ(_rotV);

  _cameraMatrix = MrotV * MrotH;

  ceVector3f eye = _spot + (_cameraMatrix * ceVector3f (0, _dist, 0));

  _camera.SetSpot(_spot);
  _camera.SetEye(eye);
  _camera.SetUp(_cameraMatrix.GetZAxis());
  _camera.FinishTransformation();
}

ceScene* SceneEditorWidget::CreateNewScene()
{
  ceScene* scene = new ceScene ();
  SetScene(scene);
  return scene;
}

void SceneEditorWidget::SetScene(ceScene *scene)
{
  if (_controlerSector && _scene)
    {
      _scene->RemoveSector(_controlerSector);
    }
  CE_SET(_scene, scene);
  if (_controlerSector && _scene)
    {
      _scene->AddSector(_controlerSector);
    }
}

ceScene* SceneEditorWidget::GetScene()
{
  return _scene;
}

const ceScene* SceneEditorWidget::GetScene() const
{
  return _scene;
}


void SceneEditorWidget::ClearTransformationHandler()
{
  if (!_transformerHandle)
    {
      return;
    }

  std::vector<ceEntityNode*>& entities = _transformerHandle->GetEntities();
  for (unsigned i=0, j=entities.size(); i<j; ++i)
    {
      _controlerSector->RemoveNode(entities[i]);
    }

  delete _transformerHandle;
  _transformerHandle = 0;
}

void SceneEditorWidget::CreateTranslationHandler()
{
  ClearTransformationHandler();
  _transformerHandle = new TranslationTransformer();
  _transformerHandle->SetTransformer(&_transformer);
  _transformerHandle->SetTransformerCoordinates(_transformerCoordinates);


  std::vector<ceEntityNode*>& entities = _transformerHandle->GetEntities();
  for (unsigned i=0, j=entities.size(); i<j; ++i)
    {
      _controlerSector->AddNode(entities[i]);
    }
  UpdateTransformationHandlerMatrix();

}

void SceneEditorWidget::CreateRotationHandle ()
{
  ClearTransformationHandler();
  _transformerHandle = new RotationTransformer();
  _transformerHandle->SetTransformer(&_transformer);
  _transformerHandle->SetTransformerCoordinates(_transformerCoordinates);


  std::vector<ceEntityNode*>& entities = _transformerHandle->GetEntities();
  for (unsigned i=0, j=entities.size(); i<j; ++i)
    {
      _controlerSector->AddNode(entities[i]);
    }

  UpdateTransformationHandlerMatrix();
}

void SceneEditorWidget::SetTransformerMode(TransformerMode mode)
{
  if (_transformerHandle && _transformerHandle->GetTransformerMode() == mode)
    {
          return;
    }
  switch (mode)
    {
    case TransformerMode_Rotation:
      CreateRotationHandle();
      break;

    case TransformerMode_Translation:
      CreateTranslationHandler();
      break;
    }

}

void SceneEditorWidget::SetTransformerCoordinates(TransformerCoordinates coordinates)
{
  _transformerCoordinates = coordinates;
  if (_transformerHandle)
    {
      _transformerHandle->SetTransformerCoordinates(coordinates);
      UpdateTransformationHandlerMatrix ();
    }
}

void SceneEditorWidget::UpdateTransformationHandlerMatrix ()
{
  if (_transformerHandle)
    {
      _transformerHandle->UpdateOriginMatrix ();
    }
}

ceSector* SceneEditorWidget::CreateControllerSector()
{
  ceSector* sector = new ceSector ();
  SetControllerSector(sector);

  SetTransformerMode(TransformerMode_Translation);

  return sector;
}

void SceneEditorWidget::SetControllerSector(ceSector *sector)
{
  if (_controlerSector && _scene)
    {
      _scene->RemoveSector(_controlerSector);
    }
  CE_SET(_controlerSector, sector);
  if (_controlerSector && _scene)
    {
      _scene->AddSector(_controlerSector);
    }
}

ceSector* SceneEditorWidget::GetControllerSector()
{
  return _controlerSector;
}

const ceSector* SceneEditorWidget::GetControllerSector() const
{
  return _controlerSector;
}

cmPhysicsWorld* SceneEditorWidget::CreatePhysicsWorld()
{
  cmPhysicsWorld* world = new cmPhysicsWorld ();
  world->Setup();
  CE_SET(_physicsWorld, world);
  return world;
}

cmPhysicsWorld* SceneEditorWidget::ClearPhysicsWorld(bool removeShapes)
{
  foreach (btRigidBody* body, _physicBodies)
    {
      _physicsWorld->RemoveRigidBody(body);
      delete body;
    }

  _physicBodies.clear();

  return _physicsWorld;
}



cmPhysicsWorld* SceneEditorWidget::GetPhysicsWorld()
{
  return _physicsWorld;
}

const cmPhysicsWorld* SceneEditorWidget::GetPhysicsWorld() const
{
  return _physicsWorld;
}

void SceneEditorWidget::InitializePhysics(ceSector *sector)
{
  if (sector)
    {
      AddPhysicsSector (sector);
    }
  else
    {

      for (ceSectorListIterator it = _scene->GetSectors().begin();
           it != _scene->GetSectors().end();
           ++it)
        {
          if (*it != _controlerSector)
            {
              AddPhysicsSector (*it);
            }
        }
    }
}

void SceneEditorWidget::AddPhysicsSector (ceSector* sector)
{
  for (NodeListIterator it = sector->GetNodes().begin();
       it != sector->GetNodes().end();
       ++it)
    {
      AddPhysicsNode(*it);
    }
}

void SceneEditorWidget::AddPhysicsNode(ceNode *node)
{
  if (!node)
    {
      return;
    }

  switch (node->GetType())
    {

    case NT_GroupNode:
      do
        {
          ceGroupNode* groupNode = static_cast<ceGroupNode*>(node);
          for (NodeListIterator it = groupNode->GetChildren().begin();
               it != groupNode->GetChildren().end();
               ++it)
            {
              AddPhysicsNode(*it);
            }
        }
      while (false);
      break;

    case NT_LODNode:
      do
        {
          ceLODNode* lodNode = static_cast<ceLODNode*>(node);
          AddPhysicsNode(lodNode->GetNode());
        }
      while (false);
      break;

    case NT_EntityNode:
      do
        {
          ceEntityNode* entityNode = static_cast<ceEntityNode*>(node);
          Geometry* geometry = static_cast<Geometry*>(entityNode->GetGeometry());
          if (!geometry)
            {
              return;
            }

          btCollisionShape* shape = 0;
          shape = geometry->GetTriangleMeshCollisionShape();
          if (!shape)
            {
              return;
            }

          btRigidBody* body = _physicsWorld->AddKinematicRigidBody(entityNode, shape);
          _physicBodies.push_back(body);

        }
      while (false);
      break;

    }


}


void SceneEditorWidget::CenterCameraOnTransformation ()
{
	if (!_transformer.IsValid ())
		{
			return;
		}
	ceVector3f dir = _camera.GetEye () - _camera.GetSpot ();
	_camera.SetSpot (_transformer.GetTransformation ().GetTranslation ());
	_camera.SetEye (_camera.GetSpot () + dir);
	_camera.FinishTransformation ();
	_spot = _camera.GetSpot ();
	repaint();
}


void SceneEditorWidget::CreateOrUpdateBoundingBoxMesh(const ceBoundingBox &bbox)
{
  struct Vertex
  {
    ceVector3f xyz;
    ceVector3f n;
    Vertex (const ceVector3f& xyz, const ceVector3f& n) : xyz(xyz), n(n) { }
  };

  const ceVector3f m = bbox.GetMin() - ceVector3f (0.5f, 0.5f, 0.5f);
  const ceVector3f M = bbox.GetMax() + ceVector3f (0.5f, 0.5f, 0.5f);
  Vertex vertices[] =
  {
    Vertex (ceVector3f (m.x, m.y, m.z), ceVector3f (0, 0, 1)),
    Vertex (ceVector3f (m.x, m.y, M.z), ceVector3f (0, 0, 1)),
    Vertex (ceVector3f (m.x, M.y, m.z), ceVector3f (0, 0, 1)),
    Vertex (ceVector3f (m.x, M.y, M.z), ceVector3f (0, 0, 1)),
    Vertex (ceVector3f (M.x, m.y, m.z), ceVector3f (0, 0, 1)),
    Vertex (ceVector3f (M.x, m.y, M.z), ceVector3f (0, 0, 1)),
    Vertex (ceVector3f (M.x, M.y, m.z), ceVector3f (0, 0, 1)),
    Vertex (ceVector3f (M.x, M.y, M.z), ceVector3f (0, 0, 1))
  };


  iDevice* device = Session::Get()->GetDevice();
  ceEngine* engine = Session::Get()->GetEngine();

  if (!_boundingBoxMesh)
    {
      unsigned short indices [] =
      {
        0, 1,
        2, 3,
        4, 5,
        6, 7,
        0, 2,
        2, 6,
        6, 4,
        4, 0,
        1, 3,
        3, 7,
        7, 5,
        5, 1
      };

      iVertexBuffer* vb = device->CreateVertexBuffer(sizeof (vertices) , vertices, BDM_Static);
      iIndexBuffer* ib = device->CreateIndexBuffer(sizeof (indices), indices, BDM_Static);

      ceVertexElement vertexElements []  =
        {
          ceVertexElement(ceProgramParameterName (PPB_Position0), DT_Float, 3, 0,  24, 0),
          ceVertexElement(ceProgramParameterName (PPB_Normal0),   DT_Float, 3, 12, 24, 0),
          ceVertexElement()
        };
      iVertexDeclaration* vd = device->CreateVertexDeclaration(vertexElements);

      _boundingBoxMesh = new ceMesh ();
      _boundingBoxMesh->Set32BitIndices(false);
      _boundingBoxMesh->SetPrimitiveType(PT_Lines);
      _boundingBoxMesh->SetIndices(ib);
      _boundingBoxMesh->SetNumberOfLines(12);
      _boundingBoxMesh->SetVertexDeclaration(vd);
      _boundingBoxMesh->SetVertices(vb);
			_boundingBoxMesh->AddRef ();
    }
  else
    {
      iVertexBuffer* vb = _boundingBoxMesh->GetVertices();
      vb->Copy(0, sizeof (vertices), vertices);
    }
  _boundingBoxMesh->SetBoundingBox(bbox);

  if (!_boundingBoxNode)
    {
      iStaticMesh* staticMesh = device->CreateStaticMesh();
      staticMesh->SetMesh(_boundingBoxMesh);

      ceGeometry* geometry = new ceGeometry (staticMesh, _boundingBoxMaterial);
      _boundingBoxNode = new ceEntityNode ();
      _boundingBoxNode->SetGeometry(geometry);
      ceMatrix4f id;
      id.SetIdentity();
      _boundingBoxNode->SetMatrix(id);
			_boundingBoxNode->AddRef ();
    }

  _boundingBoxNode->FinishTransformation(false);
}

void SceneEditorWidget::DoTransformation(int h1, int v1)
{
  float wh = (float)width () / 2.0f;
  float hh = (float)height() / 2.0f;

  v1 = height () - v1;

  int v0 = height () - _leftMousePressPositionY;
  int h0 = _leftMousePressPositionX;

  float fh0 = ((float)h0 - wh) / wh;
  float fv0 = ((float)v0 - hh) / hh;

  float fh1 = ((float)h1 - wh) / wh;
  float fv1 = ((float)v1 - hh) / hh;

  DoTransformation(fh0, fv0, fh1, fv1);
}

void SceneEditorWidget::DoTransformation(float h0, float v0, float h1, float v1)
{
  if (!_transformerHandle->IsActive())
    {
      return;
    }

  ceVector3f from = _camera.GetEye();

  ceVector3f vp0 = ceVector3f (h0 * _projector.GetRight(),
                               v0 * _projector.GetTop(),
                              -_projector.GetNear());
  vp0 = vp0 * _projector.GetFar();

  ceVector3f vp1 = ceVector3f (h1 * _projector.GetRight(),
                               v1 * _projector.GetTop(),
                              -_projector.GetNear());
  vp1 = vp1 * _projector.GetFar();

  ceVector3f at0 = from + _camera.GetMatrixInv().Rotate(vp0);
  ceVector3f at1 = from + _camera.GetMatrixInv().Rotate(vp1);


  ceRay rayFrom (from, (at0 - from).Normalized());
  ceRay rayTo   (from, (at1 - from).Normalized());

  _transformerHandle->Transform(rayFrom, rayTo);
  TransformationChanged ();
}


bool SceneEditorWidget::TestTransformerHandle(int h, int v)
{
  float wh = (float)width () / 2.0f;
  float hh = (float)height() / 2.0f;

  v = height () - v;

  float fh = ((float)h - wh) / wh;
  float fv = ((float)v - hh) / hh;

  return TestTransformerHandle(fh, fv);
}

bool SceneEditorWidget::TestTransformerHandle(float h, float v)
{
  if (!_transformerHandle)
    {
      return false;
    }

  ceVector3f from = _camera.GetEye();

  ceVector3f vp = ceVector3f (h * _projector.GetRight(),
                              v * _projector.GetTop(),
                              -_projector.GetNear());
  vp = vp * _projector.GetFar();

  ceVector3f at = from + _camera.GetMatrixInv().Rotate(vp);


  ceRay ray (from, (at - from).Normalized());

  return _transformerHandle->Test(ray);
}

void SceneEditorWidget::DoPointSelection(int h, int v, SelectMode mode)
{
  float wh = (float)width () / 2.0f;
  float hh = (float)height() / 2.0f;

  v = height () - v;

  float fh = ((float)h - wh) / wh;
  float fv = ((float)v - hh) / hh;

  DoPointSelection(fh, fv, mode);
}


void SceneEditorWidget::DoPointSelection(float h, float v, SelectMode mode)
{
  ceVector3f from = _camera.GetEye();

  ceVector3f vp = ceVector3f (h * _projector.GetRight(),
                              v * _projector.GetTop(),
                              -_projector.GetNear());
  vp = vp * _projector.GetFar();

  ceVector3f at = from + _camera.GetMatrixInv().Rotate(vp);



  ceNode* node = GetEntity(from, at);
  switch (mode)
    {
    case Select_Replace:
      SetSelectedNode(node);
      emit NodeSelected(node);
      break;

    case Select_Add:
      AddSelectedNode(node);
      emit NodeSelected(node);
      break;

    case Select_Sub:
      RemoveSelectedNode(node);
      emit NodeDeselected(node);
      break;
    }

  emit NodeSelectionChanged();
}

void SceneEditorWidget::ClearSelection ()
{
  _selectedNodes.clear();
  _transformer.Clear();
  UpdateTransformationHandlerMatrix();

  GetTransformationEditor()->UpdateGUI ();
  UpdateBoundingBoxSelection();

}

void SceneEditorWidget::SetSelectedNode (ceNode* node)
{
  _selectedNodes.clear();
  _selectedNodes.push_back(node);
  _transformer.Clear();
  _transformer.AddNode(node);
  _transformer.Finish();
  UpdateTransformationHandlerMatrix();

  GetTransformationEditor()->UpdateGUI ();
  UpdateBoundingBoxSelection();
}

void SceneEditorWidget::AddSelectedNode (ceNode* node)
{
  _selectedNodes.push_back(node);
  _transformer.AddNode(node);
  _transformer.Finish();
  UpdateTransformationHandlerMatrix();

  GetTransformationEditor()->UpdateGUI ();
  UpdateBoundingBoxSelection();
}

void SceneEditorWidget::RemoveSelectedNode(ceNode* node)
{
  std::vector<ceNode*>::iterator it;
  for (it = _selectedNodes.begin();
       it != _selectedNodes.end ();
       ++it)
    {
      ceNode* n = *it;
      if (n == node)
        {
          _selectedNodes.erase(it);
          break;
        }
    }
  _transformer.RemoveNode (node);
  _transformer.Finish();

  GetTransformationEditor()->UpdateGUI ();
  UpdateBoundingBoxSelection();
}

ceNode* SceneEditorWidget::GetSelectedNode()
{
  if (_selectedNodes.size() == 0)
    {
      return 0;
    }
  return _selectedNodes[0];
}

void SceneEditorWidget::TransformationChanged()
{
  _physicsWorld->Step();
  UpdateBoundingBoxSelection();
  repaint();
}

void SceneEditorWidget::UpdateBoundingBoxSelection()
{
  if (_selectedNodes.size() == 0)
    {
      if (_boundingBoxNode && _boundingBoxNodeVisible)
        {
          _controlerSector->RemoveNode(_boundingBoxNode);
        }
      _boundingBoxNodeVisible = false;
      repaint ();
      return;
    }

  ceBoundingBox bbox;
  bbox.Clear();
  for (unsigned i=0, j=_selectedNodes.size(); i<j; i++)
    {
      ceNode* node = _selectedNodes[i];
      if (node)
        {
          bbox.Add(((const ceNode*)node)->GetBoundingBox());
        }
    }
  bbox.Update();
  CreateOrUpdateBoundingBoxMesh(bbox);

  if (!_boundingBoxNodeVisible)
    {
      _controlerSector->AddNode(_boundingBoxNode);
      _boundingBoxNodeVisible = true;
    }

  repaint();
}


ceNode* SceneEditorWidget::GetEntity(const ceVector3f &from, const ceVector3f &at) const
{

  btCollisionWorld::AllHitsRayResultCallback callback(BTVECTOR3(from), BTVECTOR3(at));
  _physicsWorld->GetWorld()->rayTest(BTVECTOR3(from), BTVECTOR3(at), callback);


  float nearest = _projector.GetFar() * 2.0f;
  ceEntityNode* node = 0;
  for (unsigned i=0, j=callback.m_collisionObjects.size(); i<j; ++i)
    {
      btCollisionObject* obj = callback.m_collisionObjects[i];
      ceEntityNode* entity = _physicsWorld->GetEntityNode(obj);

      ceVector3f p = CEBTVECTOR3(callback.m_hitPointWorld[i]);
      float dist = (from - p).Length();

      if (dist < nearest)
        {
          nearest = dist;
          node = entity;
        }
    }

  if (!node)
    {
      return 0;
    }

  return GetSelectableNode(node);
}

ceNode* SceneEditorWidget::GetSelectableNode(ceNode *node) const
{
  if (!node)
    {
      return 0;
    }

  EditorSceneNode* esn = EditorSceneNode::FromNode(node);
  if (!esn)
    {
      return 0;
    }

  if (esn->IsSelectable())
    {
      return node;
    }

  return GetSelectableNode(node->GetParent());
}



ceMaterial* SceneEditorWidget::GetBoundingBoxMaterial()
{
  return _boundingBoxMaterial;
}

const ceCamera& SceneEditorWidget::GetCamera() const
{
  return _camera;
}

const ceProjector& SceneEditorWidget::GetProjector() const
{
  return _projector;
}

bool SceneEditorWidget::IsFullscreen() const
{
  return false;
}

ceWindowHandle SceneEditorWidget::GetWindowHandle()
{
  return winId();
}

int SceneEditorWidget::GetX() const
{
  return 0;
}

int SceneEditorWidget::GetY() const
{
  return 0;
}

unsigned SceneEditorWidget::GetWidth() const
{
  return width();
}

unsigned SceneEditorWidget::GetHeight() const
{
  return height();
}




bool SceneEditorWidget::MakeGLContextCurrent()
{
  makeCurrent();
  return QGLContext::currentContext() == context();
}

iDevice* SceneEditorWidget::GetDevice ()
{
  static iDevice* dev = 0;
	if (!dev)
		{
			dev = Session::Get ()->GetDevice ();
		}
	return dev;
}

void SceneEditorWidget::CreateBoundingBoxMaterial ()
{
  iDevice* device = GetDevice();
  const char* fragShaderCode = ""
      "void main ()                                                                   "
      "{                                                                              "
      "  gl_FragColor = vec4 (1, 1, 1, 1);                                            "
      "}                                                                              "
      "                                                                               ";
  const char* vertShaderCode = ""
      "uniform mat4 matrix_projection;                                                "
      "uniform mat4 matrix_view;                                                      "
      "uniform mat4 matrix_world;                                                     "
      "attribute vec4 vertices;                                                       "
      "                                                                               "
      "void main ()                                                                   "
      "{                                                                              "
      "  gl_Position = matrix_projection * matrix_view * matrix_world * vertices;     "
      "}                                                                              "
      "                                                                               ";
  iShader* vs = device->CreateShaderFromSource(ST_Vertex, std::string (vertShaderCode));
  iShader* fs = device->CreateShaderFromSource(ST_Fragment, std::string (fragShaderCode));
  iProgram* prog = device->CreateProgram();
  prog->AttachShader(vs);
  prog->AttachShader(fs);
  if (!prog->Link())
    {
      printf ("Cannot link: %s\n", prog->GetLinkInfoLog().c_str());
      fflush(stdout);
      prog->Release();
      vs->Release();
      fs->Release();
      return;
    }

  prog->RegisterSemantic(ceProgramParameterName("MATRIX_PROJECTION"), "matrix_projection");
  prog->RegisterSemantic(ceProgramParameterName("MATRIX_VIEW"),       "matrix_view");
  prog->RegisterSemantic(ceProgramParameterName("MATRIX_WORLD"),      "matrix_world");
  prog->RegisterSemantic(ceProgramParameterName("POSITION0"),         "vertices");

  iEffectProgram* effectProgram = device->CreateEffectProgram();
  effectProgram->SetProgram(RP_Diffuse, prog);

  iEffect* effect = device->CreateEffect();
  effect->AddEffectProgram(effectProgram);

  _boundingBoxMaterial = new ceMaterial ();
  _boundingBoxMaterial->SetEffect(effect);

}

void SceneEditorWidget::initializeGL ()
{
  iDevice* device = GetDevice ();

	_renderLoop = new ceRenderLoop ();
	_renderLoop->Initialize (device);

	_renderLoop->SetShadowMapDistances(5, 10, 20);

  CreateBoundingBoxMaterial ();
  
}

void SceneEditorWidget::resizeGL(int w, int h)
{
	float a = (float)h / (float)w;
  float ho = 0.5f;
  float ve = ho * a;
  _projector.SetLeft(-ho);
  _projector.SetRight(ho);
  _projector.SetBottom(-ve);
  _projector.SetTop(ve);
  _projector.SetNear(1.0f);
  _projector.SetFar(1024.0f);
  _projector.FinishTransformation();


}

void SceneEditorWidget::paintGL ()
{
  iDevice* device = GetDevice ();
	_renderLoop->SetViewport (device, this);
	_renderLoop->Render(device, _scene, _camera, _projector);

}


ceRay SceneEditorWidget::GetRay(int x, int y) const
{
  float hw = (float)width() / 2.0f;
  float hh = (float)height() / 2.0f;

  float fx = ((float)x - hw) / hw;
  float fy = ((float)(height () - y) - hh) / hh;

  ceVector3f from = _camera.GetEye();

  ceVector3f vp = _projector.Get (fx, fy);

  ceVector3f at = from + _camera.GetMatrixInv().Rotate(vp);

  ceVector3f dir = (at - from);
  dir.Normalize();

  return ceRay (from, dir);
}



/* ***********************************************\
 *   SceneEditor
 */


SceneEditorComponent::SceneEditorComponent (QWidget* parent)
  : QWidget (parent)
{
  _editor = new SceneEditorWidget (this);
  _buttonRotate = new QPushButton (this);
  _buttonRotate->setCheckable(true);
  _buttonRotate->setMaximumSize(28, 28);
  _buttonRotate->setFlat(true);
  _buttonTranslate = new QPushButton ("", this);
  _buttonTranslate->setCheckable(true);
  _buttonTranslate->setMaximumSize(28, 28);
  _buttonTranslate->setFlat(true);

  _buttonTranslate->setChecked(true);

  _transformGroup = new QButtonGroup (this);
  _transformGroup->addButton(_buttonRotate);
  _transformGroup->addButton(_buttonTranslate);
  _transformGroup->setExclusive(true);

  QIcon iconTranslate;
  iconTranslate.addFile(QString::fromUtf8(":/icons/media/translate.png"), QSize(), QIcon::Normal, QIcon::Off);
  _buttonTranslate->setIcon(iconTranslate);

  QIcon iconRotate;
  iconRotate.addFile(QString::fromUtf8(":/icons/media/rotate.png"), QSize(), QIcon::Normal, QIcon::Off);
  _buttonRotate->setIcon(iconRotate);


  _comboCoordinates = new QComboBox (this);
  _comboCoordinates->addItem("Local");
  _comboCoordinates->addItem("Global");


  QGridLayout* buttonLayout = new QGridLayout ();
  buttonLayout->addWidget(_buttonTranslate,     0, 1, 1, 1);
  buttonLayout->addWidget(_buttonRotate,        0, 2, 1, 1);
  buttonLayout->addWidget(_comboCoordinates,    0, 3, 1, 1);
  buttonLayout->addItem(new QSpacerItem (1, 1, QSizePolicy::Expanding, QSizePolicy::Fixed), 0, 4, 1, 1);
  buttonLayout->setMargin(0);
  buttonLayout->setSpacing(1);


  QGridLayout* layout = new QGridLayout(this);
  layout->addItem(buttonLayout, 0, 0, 1, 1);
  layout->addWidget(_editor, 1, 0, 1, 1);
  layout->setMargin(0);
  layout->setSpacing(1);

  connect (_comboCoordinates, SIGNAL(currentIndexChanged(int)), this, SLOT(on_comboCoordinates_currentIndexChanged (int)));
  connect (_transformGroup, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(on_transfromGroup_buttonClicked(QAbstractButton*)));
}



SceneEditorWidget* SceneEditorComponent::GetEditor()
{
  return _editor;
}


void SceneEditorComponent::on_comboCoordinates_currentIndexChanged (int idx)
{
  switch (idx)
    {
    case 0:
      _editor->SetTransformerCoordinates(TransformerCoordinates_Local);
      _editor->repaint();
      break;
    case 1:
      _editor->SetTransformerCoordinates(TransformerCoordinates_Global);
      _editor->repaint();
      break;
    }
}

void SceneEditorComponent::on_transfromGroup_buttonClicked(QAbstractButton *button)
{
  if (button == _buttonTranslate)
    {
      _editor->SetTransformerMode(TransformerMode_Translation);
      _editor->repaint();
    }
  else if (button == _buttonRotate)
    {
      _editor->SetTransformerMode(TransformerMode_Rotation);
      _editor->repaint();
    }
}
